package com.miyake.xml;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;


public class MyXmlParser {	
	private Integer length;
	private List<Parameter> parameters = new ArrayList<Parameter>();
	private List<String[]> yarray = new ArrayList<String[]>();
	private String name;
	private String description;
	private String provider;
	private String version;
	private String license;
	private String helpUrl;
	private List<String> titles = new ArrayList<String>();
	
	public void clear() {
		yarray.clear();
		titles.clear();
		parameters.clear();
	}
	
	public void decode(InputStream is) {
		try {
			BufferedInputStream bis = new BufferedInputStream(is);
			DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = dbfactory.newDocumentBuilder();
			Document doc = builder.parse(bis);
			Element root = doc.getDocumentElement();
			
			NodeList data = root.getElementsByTagName("Data");
			
			name = getSingleContext(root, "Name");
			description = getSingleContext(root, "Description");
			helpUrl = getSingleContext(root, "URL");
			provider = getSingleContext(root, "Provider");
			version = getSingleContext(root, "Version");
			license = getSingleContext(root, "License");
			
			NodeList paramList = root.getElementsByTagName("Parameter");
			for (int i = 0; i < paramList.getLength(); i++) {
				Node node = paramList.item(i);
				String id = node.getAttributes().getNamedItem("ID").getNodeValue();
				
				String title = getElement(node, "Title");
				String unit = getElement(node, "Unit");
				String value = getElement(node, "Value");
				String type = getElement(node, "Type");
				Parameter parameter = new Parameter(id, title, type, value, unit);
				this.getParameters().add(parameter);
				
				NodeList sel = ((Element)node).getElementsByTagName("Selection");
				for (int j = 0; j < sel.getLength(); j++) {
					parameter.getSelection().add(sel.item(j).getTextContent());
				}
			}
			
			NodeList lengthNode = root.getElementsByTagName("Length");
			if (lengthNode.getLength() > 0) {
				String i = ((Element)lengthNode.item(0)).getTextContent();
				this.length = Integer.valueOf(i);
			}

			NodeList yList = root.getElementsByTagName("Yarray");
			
			
			if (yList.getLength() > 0) {
				yarray.clear();
				titles.clear();
				for (int j = 0; j < yList.getLength(); j++) {
					Node n = yList.item(j).getAttributes().getNamedItem("Title");
					if (n != null) {
						String title = n.getNodeValue();
						titles.add(title);
					}
					NodeList item = ((Element)yList.item(j)).getChildNodes();
					String[] y = new String[item.getLength()];
					for (int i = 0; i < item.getLength(); i++) {
						y[i] = item.item(i).getTextContent();
					}
					yarray.add(y);
				}
			}		
			
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private String getElement(Node element, String tag) {
		String ret = null;
		NodeList node = ((Element)element).getElementsByTagName(tag);
		if (node.getLength() > 0) {
			ret = node.item(0).getTextContent();
		}
		if (ret == null) {
			ret = "";
		}
		return ret;
	}
	
	public String encode() {
		String ret = "";
		try {
			DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder docbuilder = dbfactory.newDocumentBuilder(); // 
			Document document = docbuilder.newDocument();          //

			Element root = document.createElement("Data");    // 
			document.appendChild(root);  
			// Name
			setSingleContext(document, root, "Name", name);
			
			// Description
			setSingleContext(document, root, "Description", description);

			// URL
			setSingleContext(document, root, "URL", helpUrl);
			
			setSingleContext(document, root, "Provider", provider);
			
			setSingleContext(document, root, "Version", version);
			
			setSingleContext(document, root, "License", license);
			// Parameter
			for (Parameter p : parameters) {
				Element param = document.createElement("Parameter");
				root.appendChild(param);
				
				param.setAttribute("ID", p.getId());
				
				if (p.getTitle() != null) {
					setSingleContext(document, param, "Title", p.getTitle());
				}
				if (p.getUnit() != null) {
					setSingleContext(document, param, "Unit", p.getUnit());
				}
				if (p.getValue() != null) {
					setSingleContext(document, param, "Value", p.getValue());
				}
				if (p.getType() != null) {
					setSingleContext(document, param, "Type", p.getType());
				}
				
				for (String s : p.getSelection()) {
					Element value = document.createElement("Selection");
					param.appendChild(value);
					value.appendChild(document.createTextNode(s));			
				}
			}
			
			// Length
			if (getLength() != null) {
				setSingleContext(document, root, "Length", getLength().toString());
			}
			
			Iterator<String> it = titles.iterator();
			for (String[] y : yarray) {
				Element dataY = document.createElement("Yarray");
				if (it.hasNext()) {
					dataY.setAttribute("Title", it.next());
				}
				root.appendChild(dataY);
				for (String s : y) {
					Element ey = document.createElement("Y");
					dataY.appendChild(ey);
					ey.appendChild(document.createTextNode(s));
				}
			}
			
			System.setProperty("javax.xml.transform.TransformerFactory",
			"com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl");
		
			TransformerFactory tfactory = TransformerFactory.newInstance(); 
			Transformer transformer = tfactory.newTransformer(); 
			StringWriter writer = new StringWriter();
			transformer.transform(new DOMSource(document), new StreamResult(writer));
			ret = writer.toString();
		}
		catch(Exception e) {
			e.printStackTrace();
		}
		return ret;
	}
	

	public void setLength(Integer length) {
		this.length = length;
	}
	
	public Integer getLength() {
		return length;
	}

	public String[] getY(int col) {
		return yarray.get(col);
	}
		
	public void addY(String[] y, String title) {
		yarray.add(y);
		titles.add(title);
	}	
	
	public void addY(String[] y) {
		yarray.add(y);
	}	
	
	public List<Parameter> getParameters() {
		return parameters;
	}

	public void setParameters(List<Parameter> parameters) {
		this.parameters = parameters;
	}

	public List<String[]> getYarray() {
		return yarray;
	}

	public void setYarray(List<String[]> yarray) {
		this.yarray = yarray;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public List<String> getTitles() {
		return titles;
	}

	public void setTitles(List<String> titles) {
		this.titles = titles;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public String getHelpUrl() {
		return helpUrl;
	}

	public void setHelpUrl(String url) {
		this.helpUrl = url;
	}
	
	private String getSingleContext(Element root, String tag) {
		NodeList node = root.getElementsByTagName(tag);
		if (node.getLength() > 0) {
			return node.item(0).getTextContent();
		}
		return null;
	}
	
	private void setSingleContext(Document document, Element root, String tag, String value) {
		if (value != null) {
			Element element = document.createElement(tag);
			root.appendChild(element);
			element.appendChild(document.createTextNode(value));
		}
	}

	public void setProvider(String provider) {
		this.provider = provider;
	}

	public String getProvider() {
		return provider;
	}

	public void setVersion(String version) {
		this.version = version;
	}

	public String getVersion() {
		return version;
	}

	public void setLicense(String license) {
		this.license = license;
	}

	public String getLicense() {
		return license;
	}
}
